package s;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.mysql.jdbc.Statement;

import cbir.Field;
import cbir.Img;
import cbir.MyFileFilter;
import cbir.Rss;
import cbir.ScaleJPG;
import cbir.Search;
import cbir.Thumb;


public class QBE extends HttpServlet{
	
	private static final long serialVersionUID = -6642198667458873473L;
	
	private Properties props;
	private String propsPath;

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		
		this.propsPath = this.getServletContext().getRealPath("/");
		this.props = new Properties();
		try {
			props.loadFromXML(new FileInputStream(propsPath + "properties.properties"));
		} catch (FileNotFoundException e) {e.printStackTrace();} 
		catch (IOException e) {e.printStackTrace();}
}
	
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {
		exe(req,res);
	}
	
	private void exe(HttpServletRequest req, HttpServletResponse res) throws IOException {
		HttpSession session = req.getSession();
		String id = session.getId();
		
		/* **  Image receiving  ** */
		String filename = new String();
		FileItem item = null;
		FileItem filedasalvare = null;
		if(ServletFileUpload.isMultipartContent(req)) {
				FileItemFactory factory = new DiskFileItemFactory();
				ServletFileUpload upload = new ServletFileUpload(factory);
	
				List<?> items = null;
				try {
					items = upload.parseRequest(req);
				} catch (FileUploadException e) {e.printStackTrace();}
			
				// Process the uploaded items
				Iterator<?> iter = items.iterator();
				
				while (iter.hasNext()) {
				    item = (FileItem) iter.next();
				    if (item.isFormField()) {} 
				    else {
				        filename = item.getName();
				        filedasalvare = item;
				    }
				}
		}else{	// ..mi lamento col client
			PrintWriter out =  res.getWriter();
			out.print("No multipart image!!");
			out.close();
			return;
		}
		
		if(props.getProperty("IS_CLEAN").compareTo("true") == 0){
			PrintWriter pw = res.getWriter();
			pw.print("FAIL");
			return;
		}


		File uploadedFile = new File( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + filename);
	    try {
			filedasalvare.write(uploadedFile);		
		} catch (Exception e) {e.printStackTrace();}
		
		String thumbname = Thumb.getThumb(filename);
		ScaleJPG.scale( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM"), this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/", filename, thumbname);
		
		Search s = new Search( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH"), this.getServletContext().getRealPath("/") + props.getProperty("INDEX_PATH"));
		
		LinkedList<Field> listaColorHistogram =  s.searchWeighted( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/" + thumbname, 1.f, 0.f, 0.f);
		LinkedList<Field> listaColorDistribution =  s.searchWeighted( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/" + thumbname, 0.f, 1.f, 0.f);
		LinkedList<Field> listaTexture =  s.searchWeighted( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM") + "thumb/" + thumbname, 0.f, 0.f, 1.f);

		ArrayList<Img> imgs = new ArrayList<Img>();		
		ListIterator<Field> lit = listaColorHistogram.listIterator();
		boolean found = false;
		
		while(lit.hasNext()){
			Field c = lit.next();
			ListIterator<Field> lit2 = listaColorDistribution.listIterator();
			found = false;
			
			Img tmpp = null;
			while(lit2.hasNext()  && found == false){
				Field c2 = lit2.next();
				if(c2.getName().compareTo( c.getName() ) == 0){
					tmpp = new Img(c.getName(), req.getServerName(), req.getContextPath());
					tmpp.setColorHistScore(c.getScore());
					tmpp.setColorDistScore(c2.getScore());
					found = true;
				}
			}
			tmpp.setColorScore();
			imgs.add(tmpp);
		}
		// ...ok!

		lit = listaTexture.listIterator();
		found = false;
		
		while(lit.hasNext()){
			Field c = lit.next();
			Iterator<Img> it = imgs.iterator();
			found = false;

			Img tmpp = null;
			while(it.hasNext() && found == false){
				tmpp = it.next();
				if(tmpp.getThumbname().compareTo( c.getName() ) == 0){
					tmpp.setTextureScore(c.getScore());
					found = true;
				}
			}
			tmpp.setSimilarityScore();
		}
		
		myOrder(imgs);
		// ...ok!
		
		if(imgs.size() == 0){
			PrintWriter out = res.getWriter();
			out.println("Empty database!");
			return;
		}
		
		
		/* **  RSS  ** */
		Connection connection = null;
		
		Statement statement;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			connection = DriverManager.getConnection(props.getProperty("DB_URL"), props.getProperty("DB_USER"), props.getProperty("DB_PASS"));
			statement = (Statement) connection.createStatement();
			
			// Preparazione query
			String query = "SELECT Filename, Height, Width FROM img WHERE";
			for(int j = 0; j < imgs.size()-1; j++){
				query = query.concat(" Filename like '" + imgs.get(j).getName() + "' OR");
			}
			query = query.concat(" FIlename = '" + imgs.get(imgs.size()-1).getName() + "';" );
			
			ResultSet rs = statement.executeQuery(query);

			found = false;
			while(rs.next()){
				String name = rs.getString("Filename");			
				
				Iterator<Img> lcc = imgs.listIterator();
				found = false;
				
				Img tmpp = null;
				while(lcc.hasNext() && found == false){
						tmpp = lcc.next();
						
						if(tmpp.getName().compareTo(name) == 0){	
							tmpp.setHeight(rs.getInt("Height"));
							tmpp.setWidth(rs.getInt("Width"));
							// add tag
							statement = (Statement) connection.createStatement();
							ResultSet r = statement.executeQuery("SELECT tag.Tag as x FROM tag, imgTag WHERE tag.IdTag = imgTag.IdTag AND imgTag.IdImg = (SELECT img.IdImg FROM img WHERE img.Filename ='"+ tmpp.getName() +"');");
							while(r.next())
								tmpp.addTag(r.getString("x"));
							found = true;
						}
				}
				
			}

		} catch (SQLException e1) {e1.printStackTrace();} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if(imgs.get(0).getSimilarityScore() == 1.)
			imgs.remove(0);		
		
		int numerodirisultati = imgs.size() > 20 ? 20 : imgs.size();	
		
		if(imgs.size() == 0)
			return;
		
		Rss r = new Rss(getServletName(), req.getServerName(), req.getContextPath());
		ArrayList<Img> truncated = new ArrayList<Img>(numerodirisultati);
		for(int h = 0; h < numerodirisultati; h++){
			imgs.get(h).setGlobalRank(imgs.indexOf(imgs.get(h)));
			truncated.add(imgs.get(h));
		}
		r.createRss(truncated);
		String rss = r.getRss().replaceAll("'","\\\\'");
	
		try {
			Class.forName("com.mysql.jdbc.Driver");
			connection= DriverManager.getConnection(props.getProperty("DB_URL"), props.getProperty("DB_USER"), props.getProperty("DB_PASS"));
			statement = (Statement) connection.createStatement();
			statement.executeUpdate("INSERT INTO sessions(Id, rss) VALUES ('"+id+"', '"+rss+"');");
		}
		catch (SQLException e) {e.printStackTrace();} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally {
			try {connection.close();} 
			catch (SQLException e) {e.printStackTrace();}
		}

		File dir = new File( this.getServletContext().getRealPath("/") + props.getProperty("IMG_PATH_NOMEM"));
		File[] fileList = dir.listFiles(new MyFileFilter());
		for(int i = 0; i < fileList.length; i++){
			if(fileList[i].delete() == false)
				System.err.println("Error in removing file/s");
		}
		
		PrintWriter pw = res.getWriter();
		pw.print(id);
	}


	private void myOrder(ArrayList<Img> x) {
		Collections.sort(x, new Comparator<Img>(){
			@Override
			public int compare(Img a, Img b) {
				if(a.getSimilarityScore() < b.getSimilarityScore())
					return +1;
				else if (a.getSimilarityScore() == b.getSimilarityScore())
					return 0;
				else
					return -1;
			}
		});
		
	}
}